package cn.getech.data.development.service.impl;


import cn.getech.data.development.constant.LastRunState;
import cn.getech.data.development.model.req.procjobstatistics.ProcJobStatisticsCompleteReq;
import cn.getech.data.development.model.req.procjobstatistics.ProcJobStatisticsGetLastReq;
import cn.getech.data.development.model.res.procjobstatistics.CompleteStatistics;
import cn.getech.data.development.model.res.procjobstatistics.CompleteStatisticsRes;
import cn.getech.data.development.model.res.procjobstatistics.OfflineDurationTop20Res;
import cn.getech.data.development.model.res.procjobstatistics.ProcJobStatisticsRes;

import cn.getech.data.intelligence.common.exception.RRException;
import cn.getech.data.intelligence.common.utils.DateUtils;
import cn.getech.data.intelligence.common.utils.NameValue;
import cn.getech.system.center.service.SysRoleService;
import cn.getech.system.center.utils.ShiroUtils;
import cn.hutool.core.collection.CollectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.getech.data.intelligence.common.utils.PageUtils2;
import cn.getech.data.intelligence.common.utils.Query;

import cn.getech.data.development.mapper.ProcJobStatisticsMapper;
import cn.getech.data.development.entity.ProcJobStatisticsEntity;
import cn.getech.data.development.service.ProcJobStatisticsService;


@Service("procJobStatisticsService")
public class ProcJobStatisticsServiceImpl extends ServiceImpl<ProcJobStatisticsMapper, ProcJobStatisticsEntity> implements ProcJobStatisticsService {
    @Autowired
    private SysRoleService sysRoleService;

    @Override
    public PageUtils2<ProcJobStatisticsEntity> queryPage(Map<String, Object> params) {
        IPage<ProcJobStatisticsEntity> page = this.page(
                new Query<ProcJobStatisticsEntity>().getPage(params),
                new QueryWrapper<ProcJobStatisticsEntity>()
        );

        return new PageUtils2<ProcJobStatisticsEntity>(page);
    }

    @Override
    public ProcJobStatisticsRes getLast(ProcJobStatisticsGetLastReq req) {
//        Map<String,Object> params = new HashMap<>();
//        params.put("procId", req.getProcId());
//
//        Long userId = ShiroUtils.getUserId();
//        boolean isAdmin = false;
//        if(req.getProcId().intValue() == 0){
//            isAdmin = sysRoleService.checkIsSupAdmin(userId);
//        }
//        int role = isAdmin ? 0 : userId.intValue();
//        params.put("role", role);//0:超级管理员 其他值是用户id
//        ProcJobStatisticsRes lastRes = baseMapper.getLast(params);
//        if(lastRes == null){
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        //获取线下任务统计
        Map<String, Object> innerParams = new HashMap<>();
        if (req.getProcId().intValue() != 0)
            innerParams.put("procId", req.getProcId());
        if(sysRoleService.isSuperAdmin(userId)){
            innerParams.put("userId", null);
        }else{
            innerParams.put("userId", userId);
        }
        innerParams.put("tenantId", tenantId);
        ProcJobStatisticsRes offLineRes = baseMapper.offlineStatistics(innerParams);
        if (offLineRes == null) {
            offLineRes = new ProcJobStatisticsRes();
        }

        ProcJobStatisticsRes realtimeRes = baseMapper.realtimeStatistics(innerParams);
        if (realtimeRes == null) {
            realtimeRes = new ProcJobStatisticsRes();
        }

        Map<String, Object> allParams = new HashMap<>();
        if(sysRoleService.isSuperAdmin(userId)){
            allParams.put("userId", null);
        }else{
            allParams.put("userId", userId);
        }
        allParams.put("tenantId", tenantId);
        Integer allTotal = baseMapper.allTotal(allParams);
        if (allTotal == null)
            allTotal = 0;

//        Integer allNotrun = baseMapper.allNotrun(allParams);
//        if (allNotrun == null)
//            allNotrun = 0;
//        allParams.put("state", 2);//2:运行
//        Integer allRun = baseMapper.allByState(allParams);
//        if (allRun == null)
//            allRun = 0;
//        allParams.put("state", 1);//1:失败
//        Integer allFail = baseMapper.allByState(allParams);
//        if (allFail == null)
//            allFail = 0;

        ProcJobStatisticsRes statisticsEntity = new ProcJobStatisticsRes();
//            statisticsEntity.setProcId(req.getProcId());
//            statisticsEntity.setCreateTime(new Date());
        statisticsEntity.setOfflineFail(offLineRes.getOfflineFail());
        statisticsEntity.setOfflineRun(offLineRes.getOfflineRun());
        statisticsEntity.setOfflineRunNotrun(offLineRes.getOfflineRunNotrun());
        statisticsEntity.setOfflineTotal(offLineRes.getOfflineTotal());
        statisticsEntity.setOfflineStop(offLineRes.getOfflineStop());
        statisticsEntity.setRealtimeFail(realtimeRes.getRealtimeFail());
        statisticsEntity.setRealtimeKilled(realtimeRes.getRealtimeKilled());
        statisticsEntity.setRealtimeRun(realtimeRes.getRealtimeRun());
        statisticsEntity.setRealtimeRunNotrun(realtimeRes.getRealtimeRunNotrun());
        statisticsEntity.setRealtimeTotal(realtimeRes.getRealtimeTotal());
        statisticsEntity.setAllFail(statisticsEntity.getOfflineFail() + statisticsEntity.getRealtimeFail());
        statisticsEntity.setAllRun(statisticsEntity.getOfflineRun()+ statisticsEntity.getRealtimeRun());
        statisticsEntity.setAllRunNotrun(statisticsEntity.getOfflineRunNotrun() + statisticsEntity.getRealtimeRunNotrun());
        statisticsEntity.setAllTotal(allTotal);
//            statisticsEntity.setRole(role);
//            save(statisticsEntity);

//            lastRes = baseMapper.getLast(params);
//        }
        return statisticsEntity;
    }

    @Override
    public List<NameValue<Integer>> offlineWeekRateOfSuccess(ProcJobStatisticsGetLastReq req) {
        Map<String,Object> params = new HashMap<>();
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        if(sysRoleService.isSuperAdmin(userId)){
            params.put("userId", null);
        }else{
            params.put("userId", userId);
        }
        params.put("tenantId", tenantId);
        if(req.getProcId().intValue() != 0)
            params.put("procId", req.getProcId());
        Date beginTime = DateUtils.getBeginDayOfWeek();
        Date endTime = DateUtils.getEndDayOfWeek();
        params.put("beginTime", DateUtils.format(beginTime, DateUtils.DATE_TIME_PATTERN));
        params.put("endTime", DateUtils.format(endTime, DateUtils.DATE_TIME_PATTERN));
        Double rateOfSuccess = baseMapper.offlineWeekRateOfSuccess(params);
        if(rateOfSuccess == null) {
            rateOfSuccess = 0.0;
        }

        List<NameValue<Integer>> list = new ArrayList<>();
        NameValue<Integer> nameValue = new NameValue<>();
        nameValue.setName("成功率");
        nameValue.setValue(rateOfSuccess.intValue());
        list.add(nameValue);
        return list;
    }

    @Override
    public List<NameValue<Integer>> offlineRunState(ProcJobStatisticsGetLastReq req) {
        Map<String,Object> offliceParams = new HashMap<>();
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        if(sysRoleService.isSuperAdmin(userId)){
            offliceParams.put("userId", null);
        }else{
            offliceParams.put("userId", userId);
        }
        offliceParams.put("tenantId", tenantId);
        if(req.getProcId().intValue() != 0)
            offliceParams.put("procId", req.getProcId());
//        Date beginTime = DateUtils.getBeginDayOfWeek();
//        Date endTime = DateUtils.getEndDayOfWeek();
//        offliceParams.put("beginTime", DateUtils.format(beginTime, DateUtils.DATE_TIME_PATTERN));
//        offliceParams.put("endTime", DateUtils.format(endTime, DateUtils.DATE_TIME_PATTERN));
        ProcJobStatisticsRes offLineRes = baseMapper.offlineRunState(offliceParams);
        if(offLineRes == null){
            offLineRes = new ProcJobStatisticsRes();
        }

        List<NameValue<Integer>> list = new ArrayList<>();
        NameValue<Integer> notNun = new NameValue<>();
        notNun.setName("未运行");
        notNun.setValue(offLineRes.getOfflineRunNotrun() - offLineRes.getOfflineRun());
        list.add(notNun);

        NameValue<Integer> run = new NameValue<>();
        run.setName("运行中");
        run.setValue(offLineRes.getOfflineRun());
        list.add(run);

        NameValue<Integer> fail = new NameValue<>();
        fail.setName("失败");
        fail.setValue(offLineRes.getOfflineFail());
        list.add(fail);

        NameValue<Integer> success = new NameValue<>();
        success.setName("成功");
        success.setValue(offLineRes.getOfflineTotal()-offLineRes.getOfflineRunNotrun()-offLineRes.getOfflineFail());
        list.add(success);

        return list;
    }

    @Override
    public CompleteStatisticsRes complete(ProcJobStatisticsCompleteReq req, boolean isOffline) {
        if(req.getType().intValue() == 1){//1:是今日
            return dayComplete(req.getProcId(), isOffline);
        } else if(req.getType().intValue() == 2){//2:是本周
            return weekComplete(req.getProcId(), isOffline);
        } else if(req.getType().intValue() == 3){//3:是本月
            return monthComplete(req.getProcId(), isOffline);
        } else {
            throw new RRException("不支持其他类型");
        }
    }

    @Override
    public List<OfflineDurationTop20Res> offlineDurationTop20(ProcJobStatisticsCompleteReq req) {
        Map<String,Object> params = new HashMap<>();
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        if(sysRoleService.isSuperAdmin(userId)){
            params.put("userId", null);
        }else{
            params.put("userId", userId);
        }
        params.put("tenantId", tenantId);
        if(req.getProcId().intValue() != 0)
            params.put("procId", req.getProcId());

        String beginTime = null;
        String endTime = null;
        if(req.getType().intValue() == 1){//1:是今日
            beginTime = DateUtils.format(DateUtils.getStartTime(), DateUtils.DATE_TIME_PATTERN);
            endTime = DateUtils.format(DateUtils.getEndTime(), DateUtils.DATE_TIME_PATTERN);
        } else if(req.getType().intValue() == 2){//2:是本周
            beginTime = DateUtils.format(DateUtils.getBeginDayOfWeek(), DateUtils.DATE_TIME_PATTERN);
            endTime = DateUtils.format(DateUtils.getEndDayOfWeek(), DateUtils.DATE_TIME_PATTERN);
        } else if(req.getType().intValue() == 3){//3:是本月
            beginTime = DateUtils.format(DateUtils.getBeginDayOfMonth(), DateUtils.DATE_TIME_PATTERN);
            endTime = DateUtils.format(DateUtils.getEndDayOfMonth(), DateUtils.DATE_TIME_PATTERN);
        } else {
            throw new RRException("不支持其他类型");
        }
        params.put("beginTime", beginTime);
        params.put("endTime", endTime);

        List<OfflineDurationTop20Res> offlineDurationTop20Res = baseMapper.offlineDurationTop20(params);
        return offlineDurationTop20Res;
    }

    private CompleteStatisticsRes dayWeekMonthCompleteReturnNull(List<String> times, List<String> times2, boolean isOffline){
        List<NameValue<Integer>> notRunReturn = new ArrayList<>();
        List<NameValue<Integer>> successReturn = new ArrayList<>();
        List<NameValue<Integer>> failReturn = new ArrayList<>();
        for(int i=0;i<times.size();i++){
            String time = times.get(i);

            if(!isOffline){
                NameValue<Integer> notRunNv = new NameValue<Integer>();
                notRunNv.setName(times2 != null ? times2.get(i) : time);
                notRunNv.setValue(0);
                notRunReturn.add(notRunNv);
            }

            NameValue<Integer> successNv = new NameValue<Integer>();
            successNv.setName(times2 != null ? times2.get(i) : time);
            successNv.setValue(0);
            successReturn.add(successNv);

            NameValue<Integer> failNv = new NameValue<Integer>();
            failNv.setName(times2 != null ? times2.get(i) : time);
            failNv.setValue(0);
            failReturn.add(failNv);
        }

        CompleteStatisticsRes res = new CompleteStatisticsRes();
        res.setTimes(times2 != null ? times2 : times);
        if(!isOffline)
            res.setNotRunValues(notRunReturn);
        res.setSuccessValues(successReturn);
        res.setFailValues(failReturn);
        return res;
    }

    private CompleteStatisticsRes dayWeekMonthComplete(List<CompleteStatistics> completeStatistics, List<String> times, List<String> times2, boolean isOffline){
        if(completeStatistics == null)
            return dayWeekMonthCompleteReturnNull(times, times2, isOffline);
        if(completeStatistics.size() == 0)
            return dayWeekMonthCompleteReturnNull(times, times2, isOffline);

        List<CompleteStatistics> notRuns = completeStatistics.stream().filter(cs -> cs.getLastRunState() == null || cs.getLastRunState() == LastRunState.NOTRUN.getCode()).collect(Collectors.toList());
        List<CompleteStatistics> successes = completeStatistics.stream().filter(cs -> cs.getLastRunState() != null && LastRunState.SUCCESS.getCode() == cs.getLastRunState()).collect(Collectors.toList());
        List<CompleteStatistics> fails = completeStatistics.stream().filter(cs -> cs.getLastRunState() != null && LastRunState.FAIL.getCode() == cs.getLastRunState()).collect(Collectors.toList());

        List<NameValue<Integer>> notRunReturn = new ArrayList<>();
        List<NameValue<Integer>> successReturn = new ArrayList<>();
        List<NameValue<Integer>> failReturn = new ArrayList<>();
        for(int i=0;i<times.size();i++){
            String time = times.get(i);

            if(!isOffline){
                Optional<CompleteStatistics> notRunFirst = notRuns.stream().filter(n -> n.getLastRunTime().equals(time)).findFirst();
                NameValue<Integer> notRunNv = new NameValue<Integer>();
                notRunNv.setName(times2 != null ? times2.get(i) : time);
                notRunNv.setValue(notRunFirst.isPresent() ? notRunFirst.get().getTotal() : 0);
                notRunReturn.add(notRunNv);
            }

            Optional<CompleteStatistics> successFirst = successes.stream().filter(n -> n.getLastRunTime().equals(time)).findFirst();
            NameValue<Integer> successNv = new NameValue<Integer>();
            successNv.setName(times2 != null ? times2.get(i) : time);
            successNv.setValue(successFirst.isPresent() ? successFirst.get().getTotal() : 0);
            successReturn.add(successNv);

            Optional<CompleteStatistics> failFirst = fails.stream().filter(n -> n.getLastRunTime().equals(time)).findFirst();
            NameValue<Integer> failNv = new NameValue<Integer>();
            failNv.setName(times2 != null ? times2.get(i) : time);
            failNv.setValue(failFirst.isPresent() ? failFirst.get().getTotal() : 0);
            failReturn.add(failNv);
        }

        CompleteStatisticsRes res = new CompleteStatisticsRes();
        res.setTimes(times2 != null ? times2 : times);
        if(!isOffline)
            res.setNotRunValues(notRunReturn);
        res.setSuccessValues(successReturn);
        res.setFailValues(failReturn);
        return res;
    }

    private CompleteStatisticsRes dayComplete(Integer procId, boolean isOffline){
        List<String> times = new ArrayList<>();
        int currHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        for(int i=0;i<=currHour;i++){
            if(i<10)
                times.add("0"+i);
            else
                times.add(""+i);
        }

        Map<String,Object> params = new HashMap<>();
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        if(sysRoleService.isSuperAdmin(userId)){
            params.put("userId", null);
        }else{
            params.put("userId", userId);
        }
        params.put("tenantId", tenantId);
        if(procId != 0)
            params.put("procId", procId);
        List<CompleteStatistics> completeStatistics = null;
        if(isOffline){//offline
            completeStatistics = baseMapper.offlineDayComplete(params);
        } else {
            completeStatistics = baseMapper.realtimeDayComplete(params);
        }

        return dayWeekMonthComplete(completeStatistics, times, null, isOffline);
    }

    private CompleteStatisticsRes weekComplete(Integer procId, boolean isOffline){
        Date beginTime = DateUtils.getBeginDayOfWeek();
        Date endTime = new Date();

        Map<String,Object> params = new HashMap<>();
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        if(sysRoleService.isSuperAdmin(userId)){
            params.put("userId", null);
        }else{
            params.put("userId", userId);
        }
        params.put("tenantId", tenantId);
        if(procId != 0)
            params.put("procId", procId);
        params.put("beginTime", DateUtils.format(beginTime, DateUtils.DATE_TIME_PATTERN));
        params.put("endTime", DateUtils.format(endTime, DateUtils.DATE_PATTERN + " 23:59:59"));

        List<String> times2 = new ArrayList<>();
        times2.add("周一");
        times2.add("周二");
        times2.add("周三");
        times2.add("周四");
        times2.add("周五");
        times2.add("周六");
        times2.add("周日");

        List<String> times = new ArrayList<>();
        Date curr = beginTime;
        while (curr.getTime() < endTime.getTime()){
            times.add(DateUtils.format(curr, DateUtils.DATE_PATTERN));
            curr = DateUtils.addDateDays(curr, 1);
        }

        times2 = CollectionUtil.sub(times2, 0, times.size());

        List<CompleteStatistics> completeStatistics = null;
        if(isOffline){
            completeStatistics = baseMapper.offlineWeekMonthComplete(params);
        } else {
            completeStatistics = baseMapper.realtimeWeekMonthComplete(params);
        }

        return dayWeekMonthComplete(completeStatistics, times, times2, isOffline);
    }

    private CompleteStatisticsRes monthComplete(Integer procId, boolean isOffline){
        Date beginTime = DateUtils.getBeginDayOfMonth();
        Date endTime = new Date();

        Map<String,Object> params = new HashMap<>();
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        if(sysRoleService.isSuperAdmin(userId)){
            params.put("userId", null);
        }else{
            params.put("userId", userId);
        }
        params.put("tenantId", tenantId);
        if(procId != 0)
            params.put("procId", procId);
        params.put("beginTime", DateUtils.format(beginTime, DateUtils.DATE_TIME_PATTERN));
        params.put("endTime", DateUtils.format(endTime, DateUtils.DATE_PATTERN + " 23:59:59"));

        List<String> times2 = new ArrayList<>();
        int currDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
        for(int i=1;i<=currDay;i++){
            if(i<10)
                times2.add("0"+i);
            else
                times2.add(""+i);
        }

        List<String> times = new ArrayList<>();
        Date curr = beginTime;
        while (curr.getTime() < endTime.getTime()){
            times.add(DateUtils.format(curr, DateUtils.DATE_PATTERN));
            curr = DateUtils.addDateDays(curr, 1);
        }

        times2 = CollectionUtil.sub(times2, 0, times.size());

        List<CompleteStatistics> completeStatistics = null;
        if(isOffline){
            completeStatistics = baseMapper.offlineWeekMonthComplete(params);
        } else {
            completeStatistics = baseMapper.realtimeWeekMonthComplete(params);
        }

        return dayWeekMonthComplete(completeStatistics, times, times2, isOffline);
    }
}
